/*
 *Copyright 2021-2023 NERCIS
 *
 *Licensed under the Apache License, Version 2.0 (the "License");
 *you may not use this file except in compliance with the License.
 *You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *Unless required by applicable law or agreed to in writing, software
 *distributed under the License is distributed on an "AS IS" BASIS,
 *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *See the License for the specific language governing permissions and
 *limitations under the License.
 */

package cn.ac.nercis.pes.service.project.imported;

import cn.ac.nercis.pes.model.dto.common.Result;
import cn.ac.nercis.pes.model.dto.project.ImportConflictDTO;
import cn.ac.nercis.pes.model.standard.SystemTargetSDTO;
import cn.ac.nercis.pes.repository.dal.knowledge.KmTargetRepository;
import cn.ac.nercis.pes.repository.dal.project.SystemTargetRepository;
import cn.ac.nercis.pes.repository.model.knowledge.KmTargetDO;
import cn.ac.nercis.pes.repository.model.project.SystemTargetDO;
import cn.ac.nercis.pes.service.utils.CheckFieldUtils;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 系统指标数据导入服务
 *
 * @author zpy
 * @version 1.0.0
 */
@Slf4j
@Service
public record SystemTargetImportService(SystemTargetRepository systemTargetRepository,
                                        KmTargetRepository kmTargetRepository) {
    @Autowired
    public SystemTargetImportService {
    }

    public Result<List<ImportConflictDTO>> checkSystemTargetData(@NonNull String systemId, List<SystemTargetSDTO> targets) {
        List<SystemTargetDO> sourceTargets = this.systemTargetRepository.findAllBySystemId(systemId);
        if (CollectionUtils.isEmpty(sourceTargets)) {
            return Result.success();
        }
        List<ImportConflictDTO> conflictData = targets.stream()
                .flatMap(st -> this.checkSystemTargetData(st, sourceTargets).stream())
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        return Result.success(conflictData);
    }

    public Result<String> importSystemTargetData(@NonNull String systemId, List<SystemTargetSDTO> targets, Boolean cover) {
        List<SystemTargetDO> sourceTargets = this.systemTargetRepository.findAllBySystemId(systemId);
        Result<String> result = Result.success();
        for (SystemTargetSDTO target : targets) {
            result = this.importSystemTargetData(systemId, target, sourceTargets, cover);
            if (!result.isSuccess()) {
                break;
            }
        }
        return result;
    }

    private List<ImportConflictDTO> checkSystemTargetData(@NonNull SystemTargetSDTO importTarget, List<SystemTargetDO> sourceTargets) {
        SystemTargetDO sourceTarget = sourceTargets.stream()
                .filter(st -> StringUtils.equals(st.getKmTargetId(), importTarget.getKmTargetId()))
                .findFirst().orElse(null);
        if (Objects.isNull(sourceTarget)) {
            return Collections.emptyList();
        }
        return CheckFieldUtils.checkField(sourceTarget, importTarget);
    }

    private Result<String> importSystemTargetData(String systemId, @NonNull SystemTargetSDTO importTarget, List<SystemTargetDO> sourceTargets, Boolean cover) {
        SystemTargetDO sourceTarget = sourceTargets.stream()
                .filter(st -> StringUtils.equals(st.getKmTargetId(), importTarget.getKmTargetId()))
                .findFirst().orElse(null);
        if (Objects.isNull(sourceTarget)) {
            return createSystemTargetData(systemId, importTarget, sourceTargets);
        } else {
            return modifySystemTargetData(sourceTarget, importTarget, cover);
        }
    }

    private Result<String> createSystemTargetData(String systemId, SystemTargetSDTO importTarget,
                                                  List<SystemTargetDO> sourceTargets) {
        KmTargetDO kmTargetDO = kmTargetRepository.findById(importTarget.getKmTargetId()).orElse(null);
        if (Objects.isNull(kmTargetDO)) {
            return Result.failed(String.format("未找到%s指标信息", importTarget.getKmName()));
        }
        SystemTargetDO systemTarget;
        if(StringUtils.isNotBlank(importTarget.getKmName())){
            systemTarget = toSystemTarget(systemId,importTarget);
        }else{
            var kt=this.kmTargetRepository.findById(importTarget.getKmTargetId()).orElse(null);
            systemTarget = toSystemTarget(systemId,importTarget,Objects.requireNonNull(kt));
        }
        systemTarget.setCreateTime(LocalDateTime.now());
        return Optional.of(systemTarget)
                .map(this.systemTargetRepository::save)
                .map(data -> {
                    sourceTargets.add(data);
                    return Result.success(data.getId());
                })
                .orElse(Result.failed(String.format("导入%s指标创建失败", importTarget.getKmName())));
    }

    private Result<String> modifySystemTargetData(SystemTargetDO sourceTarget, SystemTargetSDTO importTarget, Boolean cover) {
        sourceTarget.setIsApply(CheckFieldUtils.applyContent(sourceTarget.getIsApply(), importTarget.getIsApply(), cover));
        sourceTarget.setReasons(CheckFieldUtils.applyContent(sourceTarget.getReasons(), importTarget.getReasons(), cover));
        sourceTarget.setModifyTime(LocalDateTime.now());
        return Optional.of(sourceTarget)
                .map(this.systemTargetRepository::save)
                .map(SystemTargetDO::getId)
                .map(Result::success)
                .orElse(Result.failed(String.format("导入%s指标修改失败", importTarget.getKmName())));
    }

    private SystemTargetDO toSystemTarget(String systemId, SystemTargetSDTO importTarget){
        return SystemTargetDO.builder()
                .systemId(systemId)
                .isApply(importTarget.getIsApply())
                .reasons(importTarget.getReasons())
                .kmTargetId(importTarget.getKmTargetId())
                .kmApplyClaim(importTarget.getKmApplyClaim())
                .kmDeepness(importTarget.getKmDeepness())
                .kmIsSpecial(importTarget.getKmIsSpecial())
                .kmLevel(importTarget.getKmLevel())
                .kmName(importTarget.getKmName())
                .kmParentId(importTarget.getKmParentId())
                .kmScore(importTarget.getKmScore())
                .kmSort(importTarget.getKmSort())
                .kmType(importTarget.getKmType())
                .kmWeight(importTarget.getKmWeight())
                .build();
    }

    private SystemTargetDO toSystemTarget(String systemId, SystemTargetSDTO importTarget, KmTargetDO kt){
        return SystemTargetDO.builder()
                .systemId(systemId)
                .isApply(importTarget.getIsApply())
                .reasons(importTarget.getReasons())
                .kmTargetId(kt.getId())
                .kmApplyClaim(kt.getApplyClaim())
                .kmDeepness(kt.getDeepness())
                .kmIsSpecial(kt.getIsSpecial())
                .kmLevel(kt.getLevel())
                .kmName(kt.getName())
                .kmParentId(kt.getParentId())
                .kmScore(kt.getScore())
                .kmSort(kt.getSort())
                .kmType(kt.getType())
                .kmWeight(kt.getWeight())
                .build();
    }

}
